package com.babayetu.myclang03grammaranalysis.lexical;

import com.babayetu.myclang03grammaranalysis.model.*;

import static com.babayetu.myclang03grammaranalysis.model.ASTNodeType.*;

public class BasicGrammar {
    private String rootName;

    public BasicGrammar(String rootName) {
        this.rootName = rootName;
    }

    /**
     * 处理整数定义表达式 int age = 45;
     */
    public ASTNode doParseAsIntDeclaration(String code) throws Exception {
        //第一步：词法分析
        BasicLexer basicLexer = new BasicLexer();
        SimpleTokenReader tokenReader = basicLexer.doParse(code);

        //串行处理整数定义表达式int age = 45;
        ASTNode node =null;
        Token token = tokenReader.read(); //消耗掉int
        if (token!=null && token.getType() == TokenType.Int) {
            token = tokenReader.read();  //消耗掉age
            if (token !=null && token.getType() == TokenType.Identifier) {
                node = new ASTNode<>(ASTNodeType.IntDeclaration, token.getValue());
                token=tokenReader.read(); //消耗掉=
                if (token!=null && token.getType() == TokenType.Assignment) {
                    ASTNode child = additive(tokenReader);
                    if (child == null) {
                        throw  new Exception("=后面没有表达式");
                    } else {
                        node.addChild(child);
                    }
                }
            } else {
                throw  new Exception("此处应该是变量名");
            }

            //最后检查是不是;结尾
            if (node!=null) {
                token = tokenReader.read();
                if (token!=null && token.getType() == TokenType.SemiColon) {
                    //语句正确结束
                } else {
                    throw new Exception("语句没有以;正确结尾");
                }
            }
        } else {
            throw new Exception("此处应该是int类型关键字");
        }

        return node;
    }

    /**
     * 第一步：词法分解
     * 第二步：构建AST语法树
     * @param code
     * @return
     * @throws Exception
     */
    public ASTNode doParse(String code) throws Exception {
        BasicLexer basicLexer = new BasicLexer();
        SimpleTokenReader tokenReader = basicLexer.doParse(code);
        //当做数学表达式处理，顶层是加法表达式，第二层是乘法表达式，底层是整数
//        ASTNode<String> rootNode = processAsArithmetic(tokenReader);
        ASTNode<String> rootNode = processAddSeries(tokenReader);
        return rootNode;
    }

    /**
     * 处理数学表达式2+3*5
     * 不要求以;结尾
     *
     * @param tokenReader
     * @return
     */
    private ASTNode<String> processAsArithmetic(SimpleTokenReader tokenReader) throws Exception {
        ASTNode<String> rootASTNode = new ASTNode<>(Programm, rootName);
        ASTNode<String> child = additive(tokenReader);

        if (child != null) {
            rootASTNode.addChild(child);
        }

        return rootASTNode;
    }
    /**
     * 改良过的加法表达式解析
     * add: mul (+mul)*
     * mul: pri | mul * pri
     */
    private ASTNode<String> additiveImproved(SimpleTokenReader tokenReader) throws Exception {
        ASTNode<String> child1 = multiplicative(tokenReader);
        ASTNode node = child1;

        if (child1 != null) {
            while(true) {
                Token token = tokenReader.peek();
                if (token !=null && (token.getType() == TokenType.Plus || token.getType() == TokenType.Minus)) {
                    token = tokenReader.read();
                    ASTNode<String> child2 = multiplicative(tokenReader);
                    node = new ASTNode<>(ASTNodeType.AddExpression, token.getValue());
                    node.addChild(child1);
                    node.addChild(child2);
                    child1 = node;
                } else {
                    break;
                }
            }
        }

        return node;
    }
    /**
     * 处理数学表达式2+3+4
     * 不要求以;结尾
     *
     * @param tokenReader
     * @return
     */
    private ASTNode<String> processAddSeries(SimpleTokenReader tokenReader) throws Exception {
        ASTNode<String> rootASTNode = new ASTNode<>(Programm, rootName);
        ASTNode<String> child = additiveImproved(tokenReader);

        if (child != null) {
            rootASTNode.addChild(child);
        }

        return rootASTNode;
    }

    /**
     * 加法表达式
     * @param tokenReader
     * @return
     */
    private ASTNode<String> additive(SimpleTokenReader tokenReader) throws Exception {
        ASTNode<String> child1 = multiplicative(tokenReader);
        ASTNode<String> node = child1;

        //预读，不移除
        Token token = tokenReader.peek();
        if (child1 !=null && token !=null) {
            if (token.getType() == TokenType.Plus || token.getType() == TokenType.Minus) {
                //读取，移除
                token = tokenReader.read();
                ASTNode<String> child2 = additive(tokenReader);
                if (child2 !=null) {
                    node = new ASTNode<>(ASTNodeType.AddExpression, ((String) token.getValue()));
                    node.addChild(child1);
                    node.addChild(child2);
                } else {
                    throw new Exception("加法表达式错误，缺少右半边");
                }
            }
        }

        return node;
    }

    /**
     * 乘法表达式
     * @param tokenReader
     * @return
     */
    private ASTNode<String> multiplicative(SimpleTokenReader tokenReader) throws Exception {
        ASTNode<String> child1 = primary(tokenReader);
        ASTNode<String> node = child1;

        Token token = tokenReader.peek();
        if (child1 != null && token !=null) {
            if (token.getType() == TokenType.Star || token.getType() == TokenType.Slash) {
                token = tokenReader.read();
                ASTNode<String> child2 = primary(tokenReader);
                if (child2 != null) {
                    node = new ASTNode<>(ASTNodeType.MultipleExpression, ((String) token.getValue()));
                    node.addChild(child1);
                    node.addChild(child2);
                } else {
                    throw new Exception("乘法表达式错误，缺少右半边");
                }
            }
        }

        return node;
    }

    /**
     * 基础表达式
     * @param tokenReader
     * @return
     */
    private ASTNode<String> primary(SimpleTokenReader tokenReader) throws Exception {
        ASTNode<String> node = null;
        Token token = tokenReader.peek();
        if (token!=null) {
            if (token.getType() == TokenType.IntLiteral) {
                token = tokenReader.read();
                node = new ASTNode<>(ASTNodeType.IntValue, ((String) token.getValue()));
            } else if (token.getType() == TokenType.Identifier) {
                token = tokenReader.read();
                node = new ASTNode<>(ASTNodeType.Identifier, ((String) token.getValue()));
            } else if (token.getType() == TokenType.LeftParen) {
                tokenReader.read(); //不关心(字符，不用存
                node = additive(tokenReader); //(+)里面必须是第一级表达式，也就是加法表达式
                if (node != null) {
                    token = tokenReader.peek();
                    if (token != null && token.getType() == TokenType.RightParen) {
                        tokenReader.read(); //不关心)字符，不用存
                    } else {
                        throw new Exception("缺少右括号");
                    }
                } else {
                    throw new Exception("左括号里面缺少第一级加法表达式");
                }
            }
        }

        //简化了，不用构造primary节点，直接返回子节点，因为他还有一个子节点
        //这段话没有完全看懂
        return node;

    }
}
